Moveit + Gazebo实现联合仿真:ABB yumi双臂机器人( 一、基本仿真搭建及简单运动实现 ) |
您所在的位置:网站首页 › abb 仿真 › Moveit + Gazebo实现联合仿真:ABB yumi双臂机器人( 一、基本仿真搭建及简单运动实现 ) |
文章目录
前言搭建环境实现目标机器人选择:yumi机器人仿真目标流程安排
一、基本仿真实现模型导入Moveit配置Moveit、Gazebo建立连接(重要)建立 Gazebo 仿真环境启动文件: yumi_gazebo_world.launch配置Gazebo端轨迹接收执行文件(关节轨迹控制器)配置Gazebo端轨迹接收执行文件(关节状态控制器)Moveit端配置Moveit启动文件最终启动文件注意
机器人运动代码实现(定点、绕八字)定点运动绕八字运动绕椭圆运动
二、双臂协同仿真
前言
在学习Moveit相关教程后开始尝试动手搭建双臂机器人仿真平台,整个实现过程中多次碰壁,考虑当前网络上关于双臂机器人的仿真教程解答相对较少并不乏谬误,于是将实现流程、注意事项及个人总结分享在网络,本文不做过多教程类解释(如有需要可参考Moveit官方教程或其他博主资源),仅以记录形式方便大家和未来的自己参考。 文中代码多仅呈现关键部分,未做完整展示,项目完整代码可参考 https://github.com/Qiaozs/Moveit-Gazebo-for-yumi-ABB。 部分图片资源及参考资料来自网络,如有侵权,请联系删除。 搭建环境ubuntu20.04 ROS-noetic 提前安装好ROS对应版本下的Moveit和Gazebo 实现目标 机器人选择:yumi机器人本文选用ABB公司yumi双臂机器人,一方面因为就读院校拥有一台yumi实机,也是实验室为数不多的双臂机器人,故对其相对熟悉;另一方面ABB公司毕竟为机器人大厂,网络开源资料相对充足,且yumi确是比较知名的双臂机器人,方便在实现的过程中参考网络资料。(图片来自网络) 基于基本仿真平台实现简单的运动规划执行(定点运动、绕八字等); 基于双臂协同仿真优化运动实现效果; 另外由于npy喜欢玩蛋仔派对,遂也考虑使用yumi机器人模仿蛋仔游戏中一段人物舞蹈,比较契合机器人的双臂特点,实现难度适中,对自己也有不错的锻炼效果。 流程安排本文计划完整记录整个实现流程,故整体分为两个部分:基本仿真实现和双臂协同仿真实现。前者方便读者用来作简单机械臂仿真参考,后者具体实现双臂协同目标。主要步骤包括如下: 基本仿真实现 1、模型导入2、Moveit配置3、Moveit、Gazebo建立连接4、机器人运动代码实现(走直线、绕八字)双臂协同仿真实现 1、Moveit配置2、Moveit、Gazebo建立连接3、机器人运动代码实现(绕八字、跳舞) 一、基本仿真实现本部分基本实现 yumi 机器人在 rviz 和 gazebo 中的通讯建立,最终可以通过moveit的运动规划来实现机器人在 gazebo 中做简单动作(如走直线、绕八字)。建议读者在学习 Moveit 教程后(或学习过程中)参考本文,效果更佳。 开始之前创建 yumi_ws 工作空间 mkdir yumi_ws cd yumi_ws mkdir src catkin_make 模型导入ROS 中描述机器人模型通常使用 urdf 或 xacro 文件,两者均是标记语言,其中 urdf 相对原始, 而 xacro 对 urdf 作了一定优化,使用宏定义等方式有效减少了 urdf 文件代码的冗余性,实际使用中对二者的选择限制并不明显,本文中更多使用前者。 关于 urdf 文件,一般有以下几种方式获得: solidworks绘制模型导出网络开源 urdf 文件对于使用现有的产品级机器人建议直接从网络上下载相关机器人资源,本文使用的 yumi 机器人在可从ABB官方开源的 github 项目中下载,也可从网友上传的资源中下载。 需要的资源包括如下: 对机器人模型作简单检查,正常情况终端显示: 在当前目录下生成pdf文件用来直观认识机器人模型结构,检查无误后本步完成。 注意:网络上的机器人模型文件众多,但有不少存在细微错误无法用于后续的Moveit+Gazebo通信建立并且较难发觉(在后文中仍会提到,此处仅作提醒),不一定要使用ABB官方提供的文件,有时经过网友实践检验的反而更佳。 Moveit配置打开终端运行 rosrun moveit_setup_assistant moveit_setup_assistant启动 Moveit 配置工具,按照流程完成Moveit配置: 点击新建Moveit Configuration Package ,Browse到机器人urdf文件,点击 Load Files 键:![]() ![]() 正常情况会启动Riz仿真环境,检查是否可以对两个 group 分别做运动 plan 和 execcute: 参考网络教程,此部分需要完成多个文件的修改、添加,由于网络资料介绍、ROS版本等参差不一,整个实现中绝大多数报错来自此部分,需要读者格外注意。 准备工作:src 下新建 yumi_gazebo 功能包,包含 参数配置config 文件夹和 启动文件 launch 文件夹。 建立 Gazebo 仿真环境启动文件: yumi_gazebo_world.launch终端运行: roslaunch yumi_gazebo yumi_gazebo_world.launch启动gazebo仿真环境,正常情况为机器人在gazebo中正常显示,终端没有报错。 注意:常见的终端报错内容有: 提示某个关节不存在——机器人模型有误,建议检查改正或直接替换其他urdf文件,这个错误很容易不重视,因为实际中可能出现不存在的关节为finger关节,由于运动规划组中不涉及末端,所以一开始作者选择忽略本错误机器人模型未出现,终端报错: process has died [pid 29282, exit code 2, cmd /opt/ros/noetic/lib/controller机器人link质量或转动惯量设定有误,即也是urdf文件问题。 终端报错: [spawn_model-4] process has died [pid 19622, exit code 1, cmd /opt/ros/noetic/lib/gazebo_ros/spawn_m解决方法:删除urdf文件中的中文内容,或者前往主目录下/usr/lib/python2.7/xml/etree/ElementTree.py修改不识别中文的编码问题,可参考此处,但后者相对麻烦,建议修改前者。 终端报错:![]() 其余还可能遇到各种错误,网络上的报错解决方案也五花八门,修改起来费时费力,但作者的经验是:当遇到报错且存在上述第一条报错时,优先解决这一条,其他的有可能会随之解决。 配置Gazebo端轨迹接收执行文件(关节轨迹控制器)从此处开始,以下全部文件均默认自行新建 参数配置文件:yumi_trajectory_control.yaml yumi: arm_l_controller: type: "position_controllers/JointTrajectoryController" joints: - yumi_joint_1_l - yumi_joint_2_l - yumi_joint_7_l - yumi_joint_3_l - yumi_joint_4_l - yumi_joint_5_l - yumi_joint_6_l gains: yumi_joint_1_l: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_2_l: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_7_l: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_3_l: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_4_l: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_5_l: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_6_l: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } arm_r_controller: type: "position_controllers/JointTrajectoryController" joints: - yumi_joint_1_r - yumi_joint_2_r - yumi_joint_7_r - yumi_joint_3_r - yumi_joint_4_r - yumi_joint_5_r - yumi_joint_6_r gains: yumi_joint_1_r: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_2_r: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_7_r: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_3_r: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_4_r: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_5_r: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 } yumi_joint_6_r: { p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0 }着重注意: yaml文件第一行为命名空间,此处为yumi,需要与其他文件中的命名空间统一,否则无法建立通信。文件第二行为规划组控制器名称,同样不能随便定义,可以参考yumi_moveit_config/fake_controller.yaml中的命名方式(此为moveit配置自动生成,一般不会出错),同样需要与其他文件中的命名方式统一,否则无法建立通信。控制器启动文件yumi_trajectory_controller.launch 注意点: node中的ns参数代表上述提到的命名空间,以 /yumi 形式传入node中的name参数可写作"controller_spawner"者"arm_controller_spawner",影响不大node中args传入运动规划组控制器,此处是多臂机器人,不同规划组之间空格隔开即可 配置Gazebo端轨迹接收执行文件(关节状态控制器)参数配置文件:yumi_joint_states.yaml yumi: # Publish all joint states ----------------------------------- joint_state_controller: type: joint_state_controller/JointStateController publish_rate: 50控制器启动文件yumi_gazebo_states.launch 有些教程中将关节状态控制器和关节轨迹控制器写在一起,同样也可以实现期望效果。 Moveit端配置参数配置文件:controllers_gazebo.yaml controller_manager_ns: controller_manager controller_list: - name: yumi/arm_l_controller action_ns: follow_joint_trajectory type: FollowJointTrajectory default: true joints: - yumi_joint_1_l - yumi_joint_2_l - yumi_joint_7_l - yumi_joint_3_l - yumi_joint_4_l - yumi_joint_5_l - yumi_joint_6_l - name: yumi/arm_r_controller action_ns: follow_joint_trajectory type: FollowJointTrajectory default: true joints: - yumi_joint_1_r - yumi_joint_2_r - yumi_joint_7_r - yumi_joint_3_r - yumi_joint_4_r - yumi_joint_5_r - yumi_joint_6_rname处写作yumi/arm_l_controller,即命名空间/运动规划组控制器,有些教程中不强调写命名空间即,只写作arm_l_controller,实际中也是有无均可,但可以给自己起到提醒作用。 控制器启动文件yumi_moveit_controller_manager.launch.xml Moveit启动文件moveit_planning_execution.launch # The planning and execution components of MoveIt! configured to # publish the current configuration of the robot (simulated or real) # and the current state of the world as seen by the planner # The visualization component of MoveIt! [/yumi/joint_states] 最终启动文件本文件用于一次性启动上述的各个文件:yumi_bringup_moveit.launch 从上到下依次启动了四个launch文件。 注意以上流程为参照相关教程实现,但是参考教程实现过程中可能会遇到如下问题: 教程提到的文件不存在——许多网友在复现教程或是查找资料时都会遇到“自己没有名称一致的文件”的问题,一般这种情况直接自行新建,只要保证各launch文件之间依次按计划启动即没问题,最好明白各文件之间的关系。 举一个典型的情况:yumi_moveit_controller_manager.launch.xml(下简称y)文件在之前版本的Moveit中是随配置直接生成,而在作者使用的noetic版本的ROS中疑似被"simple_moveit_controller_manager.launch.xml"(下简称s)取代,这种情况可以选择自行新建y文件;也可以不新建,使用s文件;还有一种稳妥的方式,即新建y文件,并保证s文件内容与其一致。 同样的情况还出现在“controlers_gazebo.yaml"和 "simple_moveit_controllers.yaml"中,需要引起读者注意。终端报错:![]() ![]() 至此成功实现Moveit+Gazebo的联合仿真通讯建立,下一步可以通过编写运动规划代码来交给Moveit做运动规划,并在Gazebo中呈现。 Moveit做运动规划的好处在于其提供了运动学求解工具,并且会自动进行碰撞检测。使用Moveit做运动规划一般有三种方式:Rviz界面拖动规划、Python编程控制、C++编程控制。由于Python代码相对简洁易懂,所以本文均使用Python作为编程语言。 在基本仿真中主要实现了定点运动、绕八字运动和椭圆运动。全部代码见开源文档,此处只做部分展示。 定点运动实现定点运动有两种方案:1、设定关节角度;2、设定末端位姿 此处对设定末端姿态方式做如下展示: 末端姿态使用xyz坐标和四元数设定,此处为了避免设定多位置带来的代码冗余,定义一姿态设定函数,arm.go()等运动命令封装在move()函数中: def set_pose(x,y,z,ox,oy,oz,w): reference_frame = 'world' target_pose = PoseStamped() target_pose.header.frame_id = reference_frame target_pose.header.stamp = rospy.Time.now() target_pose.pose.position.x = x target_pose.pose.position.y = y target_pose.pose.position.z = z target_pose.pose.orientation.x = ox target_pose.pose.orientation.y = oy target_pose.pose.orientation.z = oz target_pose.pose.orientation.w = w return target_pose随后标定目标位置执行: # 标定要到达的位置点 target_pose_l_1=set_pose(0.5,0.4,0.5, 0, 0.7071068, 0, 0.7071068 ) target_pose_r_1=set_pose(0.5,-0.2,0.5, 0.7071068, 0, 0.7071068, 0 ) target_pose_l_2=set_pose(0.5,0.2,0.5, 0, 0.7071068, 0, 0.7071068 ) target_pose_r_2=set_pose(0.5,-0.4,0.5, 0.7071068, 0, 0.7071068, 0 ) target_pose_l_3=set_pose(0.3,0.5,0.5, 0, 0, 0, 1 ) target_pose_r_3=set_pose(0.3,-0.5,0.5, 0, 0, 0,1 ) # 设置机械臂终端运动的目标位姿并规划执行运动 rospy.loginfo("左臂第 1 个位置:") move(arm_l,target_pose_l_1, end_effector_link_l) rospy.loginfo("右臂第 1 个位置:") move(arm_r,target_pose_r_1, end_effector_link_r) rospy.loginfo("左臂第 2 个位置:") move(arm_l,target_pose_l_2, end_effector_link_l) rospy.loginfo("右臂第 2 个位置:") move(arm_r,target_pose_r_2, end_effector_link_r) rospy.loginfo("左臂第 3 个位置:") move(arm_l,target_pose_l_3, end_effector_link_l) rospy.loginfo("右臂第 3 个位置:") move(arm_r,target_pose_r_3, end_effector_link_r)实际操作中,机械臂末端四元数的设置相对麻烦,需要频繁得计算确定,此处给出一种相对简单方案: 可以在Rviz界面中拖动机械臂调整末端位姿,在python代码中调用move_group.get_current_pose() 函数用来提取当前机械臂位姿信息,实现方式如下(可见于get_pose.py文件) def show_pose(move_group,arm_l,arm_r): current_pose = move_group.get_current_pose() rospy.loginfo(str(current_pose.pose.position.x)+","+ str(current_pose.pose.position.y)+","+ str(current_pose.pose.position.z)+","+ str(current_pose.pose.orientation.x)+","+ str(current_pose.pose.orientation.y)+","+ str(current_pose.pose.orientation.z)+","+ str(current_pose.pose.orientation.w))终端输出的位姿信息可以直接用于设定期望末端位姿。 设定若干目标位姿后可实现如下效果: 注意:可以看到代码中分左右臂两部分编写,实际运行中,yumi机器人双臂也为先后运行,即无法做到同步运动,这是因为Moveit没有办法同时规划两个运动,即便使用两个终端同时运行两个脚本文件也无法实现(亲测,强行同时规划两个运动时,机器人双臂出现争夺现象且均无法正常运动),如此仿真完全无法发挥yumi双臂机器人优势,于是本文在下一章节给出双臂同时规划的方案。 绕八字运动区别于定点运动,八字运动强调轨迹的连续性、确定性,所以使用笛卡尔空间轨迹规划法,沿期望轨迹连续采点,plan出整体的轨迹随后execute。此处为了实现圆周运动,使用简单的三角函数原理,同样若要画椭圆运动,对三角函数系数稍作修改即可。 现定义circle_move_yz函数用来实现机械臂圆周运动: # circle_move 函数,参数为:move_group,target_pose,半径,圈数,方向(顺时针1,逆时针0),起始位置(圆心左1,圆心上2,圆心右3,圆心下4) def circle_move_yz(move_group,target_pose,radius,circles,direction,start_pose): # 初始化路点列表 waypoints = [] # 将圆弧上的路径点加入列表 # waypoints.append(target_pose.pose) centerA = target_pose.pose.position.y # 圆心 centerB = target_pose.pose.position.z for th in numpy.arange(0, circles*6.28, 0.02): if start_pose == 1: a = 3.14 if start_pose == 2: a = 4.71 if start_pose == 3: a = 0 if start_pose == 4: a = 1.57 if direction == 0:# 逆时针 target_pose.pose.position.y = centerA + radius * math.cos(th+a) target_pose.pose.position.z = centerB + radius * math.sin(th+a) wpose = deepcopy(target_pose.pose) waypoints.append(deepcopy(wpose)) if direction ==1:# 顺时针 target_pose.pose.position.y = centerA + radius * math.cos(th+a) target_pose.pose.position.z = centerB - radius * math.sin(th+a) wpose = deepcopy(target_pose.pose) waypoints.append(deepcopy(wpose)) fraction = 0.0 #路径规划覆盖率 maxtries= 100 #最大尝试规划次数 attempts = 0 #已经尝试规划次数 # 设置机器臂当前的状态作为运动初始状态 move_group.set_start_state_to_current_state() # 尝试规划一条笛卡尔空间下的路径,依次通过所有路点,完成圆弧轨迹 while fraction |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |